using System;
using System.Windows.Controls;
using Microsoft.SmallBasic.Library;
using Microsoft.Win32;
using SmallBasicFun.Quizes;
using Math = System.Math;

namespace SmallBasicFun
{
    [SmallBasicType]
    public class Homework
    {
        public static Question[] questions;
        private static string[] originalNames;
        public static Func<int> LastQuestionAnsweredCorrectly = () => ReadLastQuestionFromRegistry();
        private static string RegistryKey = "Software\\TeachingKidsProgramming\\Homework";
           
        public static int ReadLastQuestionFromRegistry()
        {
            using (RegistryKey key = Registry.CurrentUser.OpenSubKey(RegistryKey))
            {
                if (key == null)
                {
                    using (RegistryKey key2 = Registry.CurrentUser.CreateSubKey(RegistryKey))
                    {
                        
                    }
                    return 0;
                }
               var number = key.GetValue("LastQuestion");
                return number == null ? 0 : (int)number ;
            }
        }

        public static void WriteLastQuestionToRegistry(int last)
        {
            using (RegistryKey key = Registry.CurrentUser.OpenSubKey(RegistryKey,true))
            {
                key.SetValue("LastQuestion",last);
            }
        }


        public static void LoadQuestions(SmallBasicCallback callback, params string[] questionNames)
        {
            originalNames = questionNames;
            questions = new Question[questionNames.Length];
            for (int i = 0; i < questionNames.Length; i++)
            {
                questions[i] = new Question(callback.Method.DeclaringType, callback.Target, questionNames[i].ToLower());
            }
        }

        private static void StartTest()
        {
            String message = "";
            try
            {
                foreach (Question question in questions)
                {
                    ResetTortoise();
                    question.RunWithFailure();
                    question.Result = true;
                }
            }
            catch (Exception e)
            {
                message = e.Message;
            }
            DisplayResults(message);
        }

        private static void ResetTortoise()
        {
            Tortoise.SetPenColor(Colors.Black);
            Tortoise.SetAngle(0);
            Tortoise.SetSpeed(10);
            Tortoise.SetX(-300);
            Tortoise.SetY(-300);
        }

        private static void DisplayResults(String message)
        {
            Primitive background = Colors.Beige;
            Tortoise.InstantSpeed(true); 
            ProgramWindow.SetBackgroundColor(background);
            var colors = new Wheel<Primitive>(Colors.Purple, Colors.Turquoise, Colors.Green, Colors.DarkOrange);
            InitalizeTortoise();
            int castle = 580;
            int length = (castle - 20)/questions.Length;
            Uri uri = GetResourceUri("tower.png");
            Canvas canvas = GraphicsWindowHelper.GetCanvas();
            int x = castle;
            int y = 20;
            GraphicsWindowHelper.PlaceImageAt(uri, y, x, canvas);
            int direction = 1;
            bool success = true;
            for (int i = 0; i < questions.Length; i++)
            {
                Tortoise.SetPenColor(colors.GetNext());
                if (questions[i].Result)
                {
                    MoveTortoise(length, direction);
                    direction *= -1;
                }
                else
                {
                    DisplayNextMessage(message, i);
                    success = false;
                    WriteLastQuestionToRegistry(i - 1);
                    break;
                }
            }
            if (success)
            {
                DisplaySuccessMessage();
            }
        }

        private static void DisplayNextMessage(string message, int failedAt)
        {
            if (LastQuestionAnsweredCorrectly() == failedAt-2)
            {
                DisplayCongratulationsFor(failedAt);
            }
            else
            {
                DisplayErrorMessage(message, failedAt);
            }
        }

        private static void DisplayCongratulationsFor(int failedAt)
        {
            int y = 100;
            ProgramWindow.SetTextColor(Colors.Purple);
            ProgramWindow.DrawText("Congratulation! you are on the path to enlightenment", 200, y += 20);
            ProgramWindow.DrawText(String.Format("Completed [{0} of {1}]", failedAt, questions.Length), 200, y += 20);

            y = DisplayFailingTest(y, failedAt, "Try ");

           
        }

        private static void MoveTortoise(int length, int direction)
        {
            int steps = 7*2;

            double move = (Math.PI*length)/(2.0*steps);

            for (int i = 0; i < steps/2; i++)
            {
                Tortoise.Move(move);
                Tortoise.PenUp();
                Tortoise.Turn(direction*360/(steps*2));
                Tortoise.Move(move);
                Tortoise.PenDown();
                Tortoise.Turn(direction*360/(steps*2));
            }
            Tortoise.SetAngle(direction == 1 ? 180 : 0);
        }

        private static void InitalizeTortoise()
        {
            Tortoise.SetSpeed(9);
            Tortoise.SetX(20);
            Tortoise.SetY(80);
            Tortoise.SetAngle(0);
            Tortoise.Show();
            Tortoise.SetPenWidth(1);
        }

        internal static Uri GetResourceUri(string resourceName)
        {
            return new Uri(string.Format("pack://application:,,/SmallBasicFun;component/{0}", resourceName));
        }


        private static void DisplaySuccessMessage()
        {
            int y = 100;
            ProgramWindow.SetTextColor(Colors.Blue);
            ProgramWindow.DrawText(
                "Yeah! You have reached enlightenment & completed all " + questions.Length + " questions.", 200, y += 20);
            ProgramWindow.DrawText("You are now one with your homework.", 200, y += 20);
        }

        private static void DisplayErrorMessage(string message, int max)
        {
            int y = 100;
            ProgramWindow.SetTextColor(Colors.Purple);
            ProgramWindow.DrawText("Do not dispare, for you are on the path to enlightenment", 200, y += 20);
            ProgramWindow.DrawText(String.Format("Completed [{0} of {1}]", max, questions.Length), 200, y += 20);

            y = DisplayFailingTest(y, max, "Failed ");

            string[] parts = message.Split('\n');
            for (int i = 0; i < parts.Length; i++)
            {
                ProgramWindow.SetTextColor(i%2 == 0 ? Colors.Red : Colors.Gray);
                ProgramWindow.DrawText(parts[i], 200, y += 20);
            }
        }

        private static int DisplayFailingTest(int y, int max, string prefix)
        {
            ProgramWindow.SetTextColor(Colors.Red);
            Primitive fontsize = GraphicsWindow.FontSize;
            GraphicsWindow.FontSize = 16;
            ProgramWindow.DrawText(prefix, 200, y += 30);
            ProgramWindow.SetTextColor(Colors.CornflowerBlue);
            ProgramWindow.DrawText("Sub ", 260, y);
            ProgramWindow.SetTextColor(Colors.Black);
            ProgramWindow.DrawText(originalNames[max], 300, y);
            y += 10;
            GraphicsWindow.FontSize = fontsize;
            return y;
        }

      public static void CheckAnswer(Primitive actual, Primitive compareby, Primitive expected)
        {
            if (expected.IsColor())
            {
                expected = Colors.GetNameFor(expected);
            }
            if (actual.IsColor())
            {
                actual = Colors.GetNameFor(actual);
            }

            if (!actual.Equals(expected))
            {
                throw new Exception(String.Format("I wanted \n     {0} \nbut you gave me \n     {1}", expected, actual));
            }
        }

        #region Quiz Starters

        public static event SmallBasicCallback StartSimpleSquareHomeworkAt
        {
            add
            {
                LoadQuestions(value, "NumbersDoNotNeedQuotes",
                              "DefaultWidthForTheTortoise",
                              "StringsNeedQuotes", 
                              "StringsCanIncludeSpaces",
                              "DefaultColorForTheTortoise",
                              "ChangingThePenWidthTo5", 
                              "ChangingThePenColorToGreen",
                              "MovingTheTortoise100Pixels",
                              "TheTortoiseTurns21",
                              "TheTortoiseTurns15Twice",
                              "HowFastCanTheTortoiseGo",
                              "AssigningVariables", 
                              "CombiningNumbers", 
                              "CombiningText", 
                              "CombiningTextAndNumbers",
                              "CombiningTextInALoop",
                              "ForLoopsEndAtTheEnd",
                              "ForLoopsCanStartAnywhere",
                              "ForLoopsCanSkip",
                              "ForLoopsCanGoBackwards");
                StartTest();
            }

            remove { }
        }

        public static event SmallBasicCallback StartHousesHomeworkAt
        {
            add
            {
                LoadQuestions(value, "YouCanReadVariables",
                    "YouCanSaveVariables",
                    "YouCanDoMathWithVariables",
                    "YouCanChangeVariables",
                    "VariablesAreSnotStuck",
                    "YouCanAddToAVariable",
                    "YouCanSubtractFromAVariable",
                    "YouCanMultiplyVariables",
                    "YouCanDivideVariables",
                    "YouCanSetVariablesInOtherMethods",
                    "YouCanCallMethodsByName",
                    "YouCanChooseTheMethodNames",
                    "ChangingVariableInOtherMethods"
                   );
                StartTest();
            }

            remove { }
        }


        #endregion
    }
}